home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * spheres.c
- *
- * This module implements the sphere primitive.
- *
- * from Persistence of Vision(tm) Ray Tracer
- * Copyright 1996 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file. If
- * POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- * Forum. The latest version of POV-Ray may be found there as well.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- *****************************************************************************/
-
- #include "frame.h"
- #include "povray.h"
- #include "vector.h"
- #include "povproto.h"
- #include "bbox.h"
- #include "matrices.h"
- #include "objects.h"
- #include "spheres.h"
-
-
-
- /*****************************************************************************
- * Local preprocessor defines
- ******************************************************************************/
-
- #define DEPTH_TOLERANCE 1.0e-6
-
-
-
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
- static int All_Sphere_Intersections PARAMS((OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack));
- static int All_Ellipsoid_Intersections PARAMS((OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack));
- static int Inside_Sphere PARAMS((VECTOR IPoint, OBJECT *Object));
- static int Inside_Ellipsoid PARAMS((VECTOR IPoint, OBJECT *Object));
- static void Sphere_Normal PARAMS((VECTOR Result, OBJECT *Object, INTERSECTION *Inter));
- static void Ellipsoid_Normal PARAMS((VECTOR Result, OBJECT *Object, INTERSECTION *Inter));
- static void Translate_Sphere PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
- static void Rotate_Sphere PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
- static void Scale_Sphere PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
- static void Invert_Sphere PARAMS((OBJECT *Object));
-
-
-
- /*****************************************************************************
- * Local variables
- ******************************************************************************/
-
- static METHODS Sphere_Methods =
- {
- All_Sphere_Intersections,
- Inside_Sphere, Sphere_Normal,
- Copy_Sphere,
- Translate_Sphere, Rotate_Sphere,
- Scale_Sphere, Transform_Sphere, Invert_Sphere,
- Destroy_Sphere
- };
-
-
-
- static METHODS Ellipsoid_Methods =
- {
- All_Ellipsoid_Intersections,
- Inside_Ellipsoid, Ellipsoid_Normal,
- Copy_Sphere,
- Translate_Sphere, Rotate_Sphere,
- Scale_Sphere, Transform_Sphere, Invert_Sphere,
- Destroy_Sphere
- };
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * All_Sphere_Intersection
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int All_Sphere_Intersections(Object, Ray, Depth_Stack)
- OBJECT *Object;
- RAY *Ray;
- ISTACK *Depth_Stack;
- {
- register int Intersection_Found;
- DBL Depth1, Depth2;
- VECTOR IPoint;
- SPHERE *Sphere = (SPHERE *)Object;
-
- Intersection_Found = FALSE;
-
- if (Intersect_Sphere(Ray, Sphere->Center, Sqr(Sphere->Radius), &Depth1, &Depth2))
- {
- if ((Depth1 > DEPTH_TOLERANCE) && (Depth1 < Max_Distance))
- {
- VEvaluateRay(IPoint, Ray->Initial, Depth1, Ray->Direction);
-
- if (Point_In_Clip(IPoint, Object->Clip))
- {
- push_entry(Depth1, IPoint, Object, Depth_Stack);
-
- Intersection_Found = TRUE;
- }
- }
-
- if ((Depth2 > DEPTH_TOLERANCE) && (Depth2 < Max_Distance))
- {
- VEvaluateRay(IPoint, Ray->Initial, Depth2, Ray->Direction);
-
- if (Point_In_Clip(IPoint, Object->Clip))
- {
- push_entry(Depth2, IPoint, Object, Depth_Stack);
-
- Intersection_Found = TRUE;
- }
- }
- }
-
- return(Intersection_Found);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * All_Ellipsoid_Intersection
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int All_Ellipsoid_Intersections(Object, Ray, Depth_Stack)
- OBJECT *Object;
- RAY *Ray;
- ISTACK *Depth_Stack;
- {
- register int Intersection_Found;
- DBL Depth1, Depth2, len;
- VECTOR IPoint;
- RAY New_Ray;
- SPHERE *Sphere = (SPHERE *)Object;
-
- /* Transform the ray into the ellipsoid's space */
-
- MInvTransPoint(New_Ray.Initial, Ray->Initial, ((SPHERE *)Object)->Trans);
- MInvTransDirection(New_Ray.Direction, Ray->Direction, ((SPHERE *)Object)->Trans);
-
- VLength(len, New_Ray.Direction);
- VInverseScaleEq(New_Ray.Direction, len);
-
- Intersection_Found = FALSE;
-
- if (Intersect_Sphere(&New_Ray, Sphere->Center, Sqr(Sphere->Radius), &Depth1, &Depth2))
- {
- if ((Depth1 > DEPTH_TOLERANCE) && (Depth1 < Max_Distance))
- {
- VEvaluateRay(IPoint, New_Ray.Initial, Depth1, New_Ray.Direction);
-
- MTransPoint(IPoint, IPoint, ((SPHERE *)Object)->Trans);
-
- if (Point_In_Clip(IPoint, Object->Clip))
- {
- push_entry(Depth1 / len, IPoint, Object, Depth_Stack);
-
- Intersection_Found = TRUE;
- }
- }
-
- if ((Depth2 > DEPTH_TOLERANCE) && (Depth2 < Max_Distance))
- {
- VEvaluateRay(IPoint, New_Ray.Initial, Depth2, New_Ray.Direction);
-
- MTransPoint(IPoint, IPoint, ((SPHERE *)Object)->Trans);
-
- if (Point_In_Clip(IPoint, Object->Clip))
- {
- push_entry(Depth2 / len, IPoint, Object, Depth_Stack);
-
- Intersection_Found = TRUE;
- }
- }
- }
-
- return(Intersection_Found);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Intersect_Sphere
- *
- * INPUT
- *
- * Ray - Ray to test intersection with
- * Center - Center of the sphere
- * Radius2 - Squared radius of the sphere
- * Depth1 - Lower intersection distance
- * Depth2 - Upper intersection distance
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- int Intersect_Sphere(Ray, Center, Radius2, Depth1, Depth2)
- RAY *Ray;
- VECTOR Center;
- DBL Radius2;
- DBL *Depth1, *Depth2;
- {
- DBL OCSquared, t_Closest_Approach, Half_Chord, t_Half_Chord_Squared;
- VECTOR Origin_To_Center;
-
- Increase_Counter(stats[Ray_Sphere_Tests]);
-
- VSub(Origin_To_Center, Center, Ray->Initial);
-
- VDot(OCSquared, Origin_To_Center, Origin_To_Center);
-
- VDot(t_Closest_Approach, Origin_To_Center, Ray->Direction);
-
- if ((OCSquared >= Radius2) && (t_Closest_Approach < EPSILON))
- {
- return(FALSE);
- }
-
- t_Half_Chord_Squared = Radius2 - OCSquared + Sqr(t_Closest_Approach);
-
- if (t_Half_Chord_Squared > EPSILON)
- {
- Half_Chord = sqrt(t_Half_Chord_Squared);
-
- *Depth1 = t_Closest_Approach - Half_Chord;
- *Depth2 = t_Closest_Approach + Half_Chord;
-
- Increase_Counter(stats[Ray_Sphere_Tests_Succeeded]);
-
- return(TRUE);
- }
-
- return(FALSE);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Inside_Sphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int Inside_Sphere(IPoint, Object)
- VECTOR IPoint;
- OBJECT *Object;
- {
- DBL OCSquared;
- VECTOR Origin_To_Center;
-
- VSub(Origin_To_Center, ((SPHERE *)Object)->Center, IPoint);
-
- VDot(OCSquared, Origin_To_Center, Origin_To_Center);
-
- if (Test_Flag(Object, INVERTED_FLAG))
- {
- return(OCSquared > Sqr(((SPHERE *)Object)->Radius));
- }
- else
- {
- return(OCSquared < Sqr(((SPHERE *)Object)->Radius));
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Inside_Ellipsoid
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int Inside_Ellipsoid(IPoint, Object)
- VECTOR IPoint;
- OBJECT *Object;
- {
- DBL OCSquared;
- VECTOR Origin_To_Center, New_Point;
-
- /* Transform the point into the sphere's space */
-
- MInvTransPoint(New_Point, IPoint, ((SPHERE *)Object)->Trans);
-
- VSub(Origin_To_Center, ((SPHERE *)Object)->Center, New_Point);
-
- VDot(OCSquared, Origin_To_Center, Origin_To_Center);
-
- if (Test_Flag(Object, INVERTED_FLAG))
- {
- return(OCSquared > Sqr(((SPHERE *)Object)->Radius));
- }
- else
- {
- return(OCSquared < Sqr(((SPHERE *)Object)->Radius));
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Sphere_Normal
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Sphere_Normal(Result, Object, Inter)
- OBJECT *Object;
- VECTOR Result;
- INTERSECTION *Inter;
- {
- VSub(Result, Inter->IPoint, ((SPHERE *)Object)->Center);
-
- VInverseScaleEq(Result, ((SPHERE *)Object)->Radius);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Ellipsoid_Normal
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Ellipsoid_Normal(Result, Object, Inter)
- OBJECT *Object;
- VECTOR Result;
- INTERSECTION *Inter;
- {
- VECTOR New_Point;
-
- /* Transform the point into the sphere's space */
-
- MInvTransPoint(New_Point, Inter->IPoint, ((SPHERE *)Object)->Trans);
-
- VSub(Result, New_Point, ((SPHERE *)Object)->Center);
-
- MTransNormal(Result, Result, ((SPHERE *)Object)->Trans);
-
- VNormalize(Result, Result);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Copy_Shere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void *Copy_Sphere(Object)
- OBJECT *Object;
- {
- SPHERE *New;
-
- New = Create_Sphere();
-
- *New = *((SPHERE *)Object);
-
- New->Trans = Copy_Transform(((SPHERE *)Object)->Trans);
-
- return(New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Translate_Sphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Translate_Sphere(Object, Vector, Trans)
- OBJECT *Object;
- VECTOR Vector;
- TRANSFORM *Trans;
- {
- SPHERE *Sphere = (SPHERE *) Object;
-
- if (Sphere->Trans == NULL)
- {
- VAddEq(Sphere->Center, Vector);
-
- Compute_Sphere_BBox(Sphere);
- }
- else
- {
- Transform_Sphere(Object, Trans);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Rotate_Sphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Rotate_Sphere(Object, Vector, Trans)
- OBJECT *Object;
- VECTOR Vector;
- TRANSFORM *Trans;
- {
- SPHERE *Sphere = (SPHERE *) Object;
-
- if (Sphere->Trans == NULL)
- {
- MTransPoint(Sphere->Center, Sphere->Center, Trans);
-
- Compute_Sphere_BBox(Sphere);
- }
- else
- {
- Transform_Sphere(Object, Trans);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Scale_Sphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Scale_Sphere(Object, Vector, Trans)
- OBJECT *Object;
- VECTOR Vector;
- TRANSFORM *Trans;
- {
- SPHERE *Sphere = (SPHERE *) Object;
-
- if ((Vector[X] != Vector[Y]) || (Vector[X] != Vector[Z]))
- {
- if (Sphere->Trans == NULL)
- {
- Sphere->Methods = &Ellipsoid_Methods;
-
- Sphere->Trans = Create_Transform();
- }
- }
-
- if (Sphere->Trans == NULL)
- {
- VScaleEq(Sphere->Center, Vector[X]);
-
- Sphere->Radius *= Vector[X];
-
- Compute_Sphere_BBox(Sphere);
- }
- else
- {
- Transform_Sphere(Object, Trans);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Invert_Sphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Invert_Sphere(Object)
- OBJECT *Object;
- {
- Invert_Flag(Object, INVERTED_FLAG);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Sphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- SPHERE *Create_Sphere()
- {
- SPHERE *New;
-
- New = (SPHERE *)POV_MALLOC(sizeof(SPHERE), "sphere");
-
- INIT_OBJECT_FIELDS(New, SPHERE_OBJECT, &Sphere_Methods)
-
- Make_Vector(New->Center, 0.0, 0.0, 0.0);
-
- New->Radius = 1.0;
-
- New->Trans = NULL;
-
- return(New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Transform_Sphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Transform_Sphere(Object, Trans)
- OBJECT *Object;
- TRANSFORM *Trans;
- {
- SPHERE *Sphere = (SPHERE *)Object;
-
- if (Sphere->Trans == NULL)
- {
- Sphere->Methods = &Ellipsoid_Methods;
-
- Sphere->Trans = Create_Transform();
- }
-
- Compose_Transforms(Sphere->Trans, Trans);
-
- Compute_Sphere_BBox(Sphere);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Sphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * ?
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Destroy_Sphere(Object)
- OBJECT *Object;
- {
- Destroy_Transform(((SPHERE *)Object)->Trans);
-
- POV_FREE (Object);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Compute_Sphere_BBox
- *
- * INPUT
- *
- * Sphere - Sphere
- *
- * OUTPUT
- *
- * Sphere
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Calculate the bounding box of a sphere.
- *
- * CHANGES
- *
- * Aug 1994 : Creation.
- *
- ******************************************************************************/
-
- void Compute_Sphere_BBox(Sphere)
- SPHERE *Sphere;
- {
- Make_BBox(Sphere->BBox, Sphere->Center[X] - Sphere->Radius, Sphere->Center[Y] - Sphere->Radius, Sphere->Center[Z] - Sphere->Radius,
- 2.0 * Sphere->Radius, 2.0 * Sphere->Radius, 2.0 * Sphere->Radius);
-
- if (Sphere->Trans != NULL)
- {
- Recompute_BBox(&Sphere->BBox, Sphere->Trans);
- }
- }
-